{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.1.0\n",
      "sys.version_info(major=3, minor=6, micro=9, releaselevel='final', serial=0)\n",
      "matplotlib 3.1.3\n",
      "numpy 1.18.1\n",
      "pandas 1.0.1\n",
      "sklearn 0.22.1\n",
      "tensorflow 2.1.0\n",
      "tensorflow_core.python.keras.api._v2.keras 2.2.4-tf\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\n数据名称定义：\\ninput，表示会输入到模型中的数据\\nlabel，表示对应的数据结果\\npred，表示模型的输出\\n'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "import tensorflow as tf\n",
    "\n",
    "from tensorflow import keras\n",
    "\n",
    "print(tf.__version__)\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, tf, keras:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "'''\n",
    "数据名称定义：\n",
    "input，表示会输入到模型中的数据\n",
    "label，表示对应的数据结果\n",
    "pred，表示模型的输出\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".. _california_housing_dataset:\n",
      "\n",
      "California Housing dataset\n",
      "--------------------------\n",
      "\n",
      "**Data Set Characteristics:**\n",
      "\n",
      "    :Number of Instances: 20640\n",
      "\n",
      "    :Number of Attributes: 8 numeric, predictive attributes and the target\n",
      "\n",
      "    :Attribute Information:\n",
      "        - MedInc        median income in block\n",
      "        - HouseAge      median house age in block\n",
      "        - AveRooms      average number of rooms\n",
      "        - AveBedrms     average number of bedrooms\n",
      "        - Population    block population\n",
      "        - AveOccup      average house occupancy\n",
      "        - Latitude      house block latitude\n",
      "        - Longitude     house block longitude\n",
      "\n",
      "    :Missing Attribute Values: None\n",
      "\n",
      "This dataset was obtained from the StatLib repository.\n",
      "http://lib.stat.cmu.edu/datasets/\n",
      "\n",
      "The target variable is the median house value for California districts.\n",
      "\n",
      "This dataset was derived from the 1990 U.S. census, using one row per census\n",
      "block group. A block group is the smallest geographical unit for which the U.S.\n",
      "Census Bureau publishes sample data (a block group typically has a population\n",
      "of 600 to 3,000 people).\n",
      "\n",
      "It can be downloaded/loaded using the\n",
      ":func:`sklearn.datasets.fetch_california_housing` function.\n",
      "\n",
      ".. topic:: References\n",
      "\n",
      "    - Pace, R. Kelley and Ronald Barry, Sparse Spatial Autoregressions,\n",
      "      Statistics and Probability Letters, 33 (1997) 291-297\n",
      "\n",
      "(20640, 8)\n",
      "(20640,)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\n可以看出，训练数据是 (20640,8) ，说明一共有20640份数据，每份数据有8个特征值\\nlabel数据是(20640,)表示，每个label的值就是一个标量，总的数据格式是个向量格式\\n'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "## 从sklearn.datasets中导入 fetch_califor_housing函数，这个函数的功能就是下载训练数据\n",
    "from sklearn.datasets import fetch_california_housing\n",
    "\n",
    "## 调用函数，下载文件；判断指定文件是否存在，如果存在，直接读取文件；不存在则去互联网上下载\n",
    "housing = fetch_california_housing()\n",
    "\n",
    "## 查看数据对象的描述\n",
    "print(housing.DESCR)\n",
    "\n",
    "## 查看input数据的shape\n",
    "print(housing.data.shape)\n",
    "\n",
    "## 查看label数据，既然能调用shape，说明是numpy格式\n",
    "print(housing.target.shape)\n",
    "\n",
    "'''\n",
    "可以看出，训练数据是 (20640,8) ，说明一共有20640份数据，每份数据有8个特征值\n",
    "label数据是(20640,)表示，每个label的值就是一个标量，总的数据格式是个向量格式\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "array([[ 8.32520000e+00,  4.10000000e+01,  6.98412698e+00,\n",
      "         1.02380952e+00,  3.22000000e+02,  2.55555556e+00,\n",
      "         3.78800000e+01, -1.22230000e+02],\n",
      "       [ 8.30140000e+00,  2.10000000e+01,  6.23813708e+00,\n",
      "         9.71880492e-01,  2.40100000e+03,  2.10984183e+00,\n",
      "         3.78600000e+01, -1.22220000e+02],\n",
      "       [ 7.25740000e+00,  5.20000000e+01,  8.28813559e+00,\n",
      "         1.07344633e+00,  4.96000000e+02,  2.80225989e+00,\n",
      "         3.78500000e+01, -1.22240000e+02],\n",
      "       [ 5.64310000e+00,  5.20000000e+01,  5.81735160e+00,\n",
      "         1.07305936e+00,  5.58000000e+02,  2.54794521e+00,\n",
      "         3.78500000e+01, -1.22250000e+02],\n",
      "       [ 3.84620000e+00,  5.20000000e+01,  6.28185328e+00,\n",
      "         1.08108108e+00,  5.65000000e+02,  2.18146718e+00,\n",
      "         3.78500000e+01, -1.22250000e+02]])\n",
      "array([4.526, 3.585, 3.521, 3.413, 3.422])\n"
     ]
    }
   ],
   "source": [
    "## 导入pprint，更好的显示数据\n",
    "import pprint\n",
    "\n",
    "pprint.pprint(housing.data[0:5])\n",
    "pprint.pprint(housing.target[0:5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(11610, 8) (11610,)\n",
      "(3870, 8) (3870,)\n",
      "(5160, 8) (5160,)\n"
     ]
    }
   ],
   "source": [
    "## 将训练数据进行划分，因为读取出来的文件是没有划分训练数据，验证数据，测试数据\n",
    "## 注意返回数据的位置\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "x_train_all, x_test, y_train_all, y_test = train_test_split(\n",
    "    ## 传入总的input数据和 label数据，默认返回出来的test数据占比 0.25\n",
    "    housing.data, housing.target, random_state = 7)\n",
    "\n",
    "## 将训练数据再次划分为 train 和 valid\n",
    "x_train, x_valid, y_train, y_valid = train_test_split(\n",
    "    x_train_all, y_train_all, random_state = 11)\n",
    "print(x_train.shape, y_train.shape)\n",
    "print(x_valid.shape, y_valid.shape)\n",
    "print(x_test.shape, y_test.shape)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "## 将数据进行归一化处理  StandardScaler\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "\n",
    "## 创建scaler对象\n",
    "scaler = StandardScaler()\n",
    "\n",
    "## 对x_train对象调用 fit_transform表示 后面归一化时的均值和方差就按照x_train里面的均值方差来处理\n",
    "x_train_scaled = scaler.fit_transform(x_train)\n",
    "x_valid_scaled = scaler.transform(x_valid)\n",
    "x_test_scaled = scaler.transform(x_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential_2\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "dense_5 (Dense)              (None, 30)                270       \n",
      "_________________________________________________________________\n",
      "dense_6 (Dense)              (None, 30)                930       \n",
      "_________________________________________________________________\n",
      "dense_7 (Dense)              (None, 1)                 31        \n",
      "=================================================================\n",
      "Total params: 1,231\n",
      "Trainable params: 1,231\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "## 创建模型，使用keras.models.Sequential 创建连续layer的模型\n",
    "model = keras.models.Sequential([\n",
    "    ## 创建全连接层，neural个数为30个，激活函数为relu，\n",
    "    keras.layers.Dense(30, activation='relu',\n",
    "                       ## input_shape表示输入数据的特征值\n",
    "                       ## x_train.shape是个tulpe，x_train.shape[1:] => (8,) 也是个tuple\n",
    "                       input_shape=x_train.shape[1:]),\n",
    "     ## 创建全连接层，neural个数为30个，激活函数为relu，\n",
    "    keras.layers.Dense(30, activation='relu',\n",
    "                       ## input_shape表示输入数据的特征值\n",
    "                       ## x_train.shape是个tulpe，x_train.shape[1:] => (8,) 也是个tuple\n",
    "                ),\n",
    "    \n",
    "    ## 输出层，一个neural\n",
    "    keras.layers.Dense(1),\n",
    "])\n",
    "model.summary()\n",
    "\n",
    "## 编译模型，损失函数是 mean_squared_error ,  优化器是 sgd 梯度下降\n",
    "model.compile(loss=\"mean_squared_error\", optimizer=\"Adam\",\n",
    "             metrics=['accuracy'])\n",
    "\n",
    "## 指定模型callbacks，当损失值小于指定值多次后，停止训练\n",
    "callbacks = [keras.callbacks.EarlyStopping(\n",
    "    patience=5, min_delta=1e-2)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 11610 samples, validate on 3870 samples\n",
      "Epoch 1/10\n",
      "11610/11610 [==============================] - 2s 170us/sample - loss: 1.4034 - accuracy: 0.0029 - val_loss: 0.6865 - val_accuracy: 0.0021\n",
      "Epoch 2/10\n",
      "11610/11610 [==============================] - 1s 51us/sample - loss: 0.5111 - accuracy: 0.0031 - val_loss: 0.4591 - val_accuracy: 0.0023\n",
      "Epoch 3/10\n",
      "11610/11610 [==============================] - 1s 52us/sample - loss: 0.4107 - accuracy: 0.0031 - val_loss: 0.4158 - val_accuracy: 0.0023\n",
      "Epoch 4/10\n",
      "11610/11610 [==============================] - 1s 51us/sample - loss: 0.3859 - accuracy: 0.0031 - val_loss: 0.3983 - val_accuracy: 0.0023\n",
      "Epoch 5/10\n",
      "11610/11610 [==============================] - 1s 49us/sample - loss: 0.3747 - accuracy: 0.0031 - val_loss: 0.3796 - val_accuracy: 0.0023\n",
      "Epoch 6/10\n",
      "11610/11610 [==============================] - 1s 50us/sample - loss: 0.3665 - accuracy: 0.0031 - val_loss: 0.3764 - val_accuracy: 0.0023\n",
      "Epoch 7/10\n",
      "11610/11610 [==============================] - 1s 51us/sample - loss: 0.3506 - accuracy: 0.0031 - val_loss: 0.3600 - val_accuracy: 0.0023\n",
      "Epoch 8/10\n",
      "11610/11610 [==============================] - 1s 51us/sample - loss: 0.3480 - accuracy: 0.0031 - val_loss: 0.3522 - val_accuracy: 0.0023\n",
      "Epoch 9/10\n",
      "11610/11610 [==============================] - 1s 55us/sample - loss: 0.3372 - accuracy: 0.0031 - val_loss: 0.3456 - val_accuracy: 0.0023\n",
      "Epoch 10/10\n",
      "11610/11610 [==============================] - 1s 51us/sample - loss: 0.3304 - accuracy: 0.0031 - val_loss: 0.3439 - val_accuracy: 0.0023\n"
     ]
    }
   ],
   "source": [
    "## 调用fit函数训练模型，返回训训练过程中 的 loss值变化\n",
    "## 需要传入的参数：(train数据 包括input和label),（验证数据 包括 input和label）\n",
    "## 返回的history中 history.history 就是dict字典类型，存储着各个值的每一次epoch的变化情况\n",
    "## 因为是dict字典类型能够被转换为pandas.DataFrame的格式，能够被画图画出来\n",
    "history = model.fit(x_train_scaled, y_train,\n",
    "                    validation_data = (x_valid_scaled, y_valid),\n",
    "                    ##  指定完整遍历数据100次\n",
    "                    epochs = 10,\n",
    "                    ## 指定callback，earlystop\n",
    "                    callbacks = callbacks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "def plot_learning_curves(history):\n",
    "    ## 创建pandas的DataFrame数据，该数据格式可以由\n",
    "    ## figsize指图片尺寸大小，单位英寸\n",
    "    pd.DataFrame(history.history).plot(figsize=(8, 5))\n",
    "    \n",
    "    ## 在表格中加入线\n",
    "    plt.grid(True)\n",
    "    \n",
    "    ## 设置纵坐标范围\n",
    "    plt.gca().set_ylim(0, 1)\n",
    "    \n",
    "    ## 显示图片\n",
    "    plt.show()\n",
    "plot_learning_curves(history)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "A target array with shape (5160, 8) was passed for an output of shape (None, 1) while using as loss `mean_squared_error`. This loss expects targets to have the same shape as the output.",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-35-17f80ced3957>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      8\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      9\u001b[0m \u001b[0;31m## 传入数据需要是 [None,8]，\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m \u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mevaluate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx_test_scaled\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx_test_scaled\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m~/environment/new_tf_py3/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training.py\u001b[0m in \u001b[0;36mevaluate\u001b[0;34m(self, x, y, batch_size, verbose, sample_weight, steps, callbacks, max_queue_size, workers, use_multiprocessing)\u001b[0m\n\u001b[1;32m    928\u001b[0m         \u001b[0mmax_queue_size\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmax_queue_size\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    929\u001b[0m         \u001b[0mworkers\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mworkers\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 930\u001b[0;31m         use_multiprocessing=use_multiprocessing)\n\u001b[0m\u001b[1;32m    931\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    932\u001b[0m   def predict(self,\n",
      "\u001b[0;32m~/environment/new_tf_py3/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training_v2.py\u001b[0m in \u001b[0;36mevaluate\u001b[0;34m(self, model, x, y, batch_size, verbose, sample_weight, steps, callbacks, max_queue_size, workers, use_multiprocessing, **kwargs)\u001b[0m\n\u001b[1;32m    488\u001b[0m         \u001b[0msample_weight\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msample_weight\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msteps\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msteps\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcallbacks\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcallbacks\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    489\u001b[0m         \u001b[0mmax_queue_size\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmax_queue_size\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mworkers\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mworkers\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 490\u001b[0;31m         use_multiprocessing=use_multiprocessing, **kwargs)\n\u001b[0m\u001b[1;32m    491\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    492\u001b[0m   def predict(self, model, x, batch_size=None, verbose=0, steps=None,\n",
      "\u001b[0;32m~/environment/new_tf_py3/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training_v2.py\u001b[0m in \u001b[0;36m_model_iteration\u001b[0;34m(self, model, mode, x, y, batch_size, verbose, sample_weight, steps, callbacks, max_queue_size, workers, use_multiprocessing, **kwargs)\u001b[0m\n\u001b[1;32m    424\u001b[0m           \u001b[0mmax_queue_size\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmax_queue_size\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    425\u001b[0m           \u001b[0mworkers\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mworkers\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 426\u001b[0;31m           use_multiprocessing=use_multiprocessing)\n\u001b[0m\u001b[1;32m    427\u001b[0m       \u001b[0mtotal_samples\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_get_total_number_of_samples\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0madapter\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    428\u001b[0m       \u001b[0muse_sample\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtotal_samples\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/new_tf_py3/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training_v2.py\u001b[0m in \u001b[0;36m_process_inputs\u001b[0;34m(model, mode, x, y, batch_size, epochs, sample_weights, class_weights, shuffle, steps, distribution_strategy, max_queue_size, workers, use_multiprocessing)\u001b[0m\n\u001b[1;32m    644\u001b[0m     \u001b[0mstandardize_function\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    645\u001b[0m     x, y, sample_weights = standardize(\n\u001b[0;32m--> 646\u001b[0;31m         x, y, sample_weight=sample_weights)\n\u001b[0m\u001b[1;32m    647\u001b[0m   \u001b[0;32melif\u001b[0m \u001b[0madapter_cls\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mdata_adapter\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mListsOfScalarsDataAdapter\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    648\u001b[0m     \u001b[0mstandardize_function\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mstandardize\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/new_tf_py3/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training.py\u001b[0m in \u001b[0;36m_standardize_user_data\u001b[0;34m(self, x, y, sample_weight, class_weight, batch_size, check_steps, steps_name, steps, validation_split, shuffle, extract_tensors_from_dataset)\u001b[0m\n\u001b[1;32m   2381\u001b[0m         \u001b[0mis_dataset\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mis_dataset\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2382\u001b[0m         \u001b[0mclass_weight\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mclass_weight\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2383\u001b[0;31m         batch_size=batch_size)\n\u001b[0m\u001b[1;32m   2384\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2385\u001b[0m   def _standardize_tensors(self, x, y, sample_weight, run_eagerly, dict_inputs,\n",
      "\u001b[0;32m~/environment/new_tf_py3/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training.py\u001b[0m in \u001b[0;36m_standardize_tensors\u001b[0;34m(self, x, y, sample_weight, run_eagerly, dict_inputs, is_dataset, class_weight, batch_size)\u001b[0m\n\u001b[1;32m   2487\u001b[0m           \u001b[0;31m# Additional checks to avoid users mistakenly using improper loss fns.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2488\u001b[0m           training_utils.check_loss_and_target_compatibility(\n\u001b[0;32m-> 2489\u001b[0;31m               y, self._feed_loss_fns, feed_output_shapes)\n\u001b[0m\u001b[1;32m   2490\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2491\u001b[0m       sample_weights, _, _ = training_utils.handle_partial_sample_weights(\n",
      "\u001b[0;32m~/environment/new_tf_py3/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/training_utils.py\u001b[0m in \u001b[0;36mcheck_loss_and_target_compatibility\u001b[0;34m(targets, loss_fns, output_shapes)\u001b[0m\n\u001b[1;32m    808\u001b[0m           raise ValueError('A target array with shape ' + str(y.shape) +\n\u001b[1;32m    809\u001b[0m                            \u001b[0;34m' was passed for an output of shape '\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 810\u001b[0;31m                            \u001b[0;34m' while using as loss `'\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mloss_name\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34m'`. '\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    811\u001b[0m                            \u001b[0;34m'This loss expects targets to have the same shape '\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    812\u001b[0m                            'as the output.')\n",
      "\u001b[0;31mValueError\u001b[0m: A target array with shape (5160, 8) was passed for an output of shape (None, 1) while using as loss `mean_squared_error`. This loss expects targets to have the same shape as the output."
     ]
    }
   ],
   "source": [
    "## 调用evaluate函数，传入测试数据\n",
    "## 模型传入的数据一定要是 np.array 或者是 dataset这样的\n",
    "\n",
    "# print(y_test)\n",
    "# print(y_test[:,np.newaxis])\n",
    "# print(y_test[:,np.newaxis][:,np.newaxis])\n",
    "\n",
    "\n",
    "## 传入数据需要是 [None,8]，二维的，\n",
    "## 验证数据 [None,1]，可以是一维向量，也可以是二维矩阵，只要最小维度下只有一个值就好\n",
    "model.evaluate(x_test_scaled, x_test_scaled)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
